package kyo;

import java.util.*;

public class Input<D> {
    //Kyo.init初始化只能被调用一次，而Input类可以实例化多个
    //initFlags标识Kyo.init是否初始化过
    private static boolean initFlags = false;
    //用于保存注册按键的列表, 通过键值直接索引按键回调
    private Map<Keysym, InputRun> keyMap = new HashMap<Keysym, InputRun>();
    //用于保存通用处理按键回调
    private InputRun commonRun = null;
    // 用于保存处理按键功能回调参数
    private D runData = null;
    // 用于保存输入过的字符
    private StringBuilder line = new StringBuilder();
    // 标识退出按键
    Keysym quitKey = Keysym.ESC;

    public Input() {
        this(Keysym.ESC, null, null);
    }

    public Input(Keysym quitKey) {
        this(quitKey, null, null);
    }

    public Input(InputRun commonRun, D runData) {
        this(Keysym.ESC, commonRun, runData);
    }

    public Input(Keysym quitKey, InputRun commonRun, D runData) {
        if (!initFlags) {
            Kyo.init();
            initFlags = true;
        }
        set(quitKey, commonRun, runData);
    }


    public Input set(Keysym quitKey, InputRun commonRun, D runData) {
        setQuitKey(quitKey);
        setRun(commonRun);
        setData(runData);
        return this;
    }

    public Input setQuitKey(Keysym quitKey) {
        this.quitKey = quitKey;
        return this;
    }

    public Input setData(D runData) {
        this.runData = runData;
        return this;
    }

    public Input setRun(InputRun commonRun) {
        this.commonRun = commonRun;
        return this;
    }


    //获取一个按键功能
    //封装Kyo.key方法，转换到枚举对象
    public Keysym getKey(String prompt) {
        int val = -1;
        while (true) {
            System.out.print(prompt);
            val = Kyo.key();
            if (val != -1)
                break;
        }

        return Keysym.key(val);
    }

    //重载方法支持无参运行
    public Keysym getKey() {
        return getKey("");
    }

    //注册按键功能 按键绑定回调操作
    public Input regKey(Keysym sym, InputRun iRun) {
        iRun = (iRun == null) ? this.commonRun : iRun;
        keyMap.put(sym, iRun);
        return this;
    }

    //注册多个按键绑定全局回调操作
    public Input regKey(Keysym ... sym) {
        for (Keysym s : sym) {
            regKey(s, null);
        }
        return this;
    }

    //运行获取按键操作进行捕捉处理
    //afterRun 为未注册按键的回调操作, 可以为null
    public RunState run(InputRun afterRun) {
        RunState rState = null;

        try {
            Keysym sym = null;
            InputRun iRun = null;

            while (true) {
                sym = Keysym.key(Kyo.key());
                if (sym == quitKey) {
                    break;
                }
                iRun = keyMap.get(sym);
                if (iRun == null && afterRun != null) {
                    afterRun.handle(sym, line, null);
                } else if(iRun != null) {
                    rState = iRun.handle(sym, line, runData);
                    if (rState != RunState.RUNNING)
                        break;
                }
            }
        } catch (Exception e) {
            close();
            throw e;
        }
        return rState;
    }

    //重载处理捕捉按键功能方法，支持无参无回调
    public RunState run() {
        return run(null);
    }

    //获取一行字符串并且支持注册按键捕捉功能
    public String getLine(String prompt, Object ... obj) {
        line.delete(0, line.length());
        System.out.printf(prompt, obj);
        setQuitKey(Keysym.RETURN);
        run(new InputRun(){
            public <D> RunState handle(Keysym sym, StringBuilder s, D data) {
                char c = (char)sym.getSym();
                System.out.print(c);
                line.append(c);
                return RunState.RUNNING;
            }
        });
        System.out.println();

        return line.toString();
    }

    //还原终端配置(开启回显和缓冲区)
    public void close() {
        Kyo.exit();
    }
}
